/*
实验8-5 拆积木
分数 30
作者 陈越
单位 浙江大学

cjm.png

给定一个由带编号的积木搭成的长方体。其中每块积木的厚度都一样，由若干个单位边长的相邻方块组成（相邻是指两个方块有一面重合）。现在要求将这个长方体中的积木一块一块拆掉。每块积木只能从顶端取出，并且取出时不能移动还在长方体中的其它积木。请你给出一个拆积木的顺序。当然这种顺序可能是不唯一的，我们规定当有多种选择时，总是取出编号最小的那个。
输入格式:

输入第一行给出两个正整数 N 和 M（1≤N,M≤1000），分别为长方体的高度和宽度。随后 N
行，每行给出 M 个整数，为对应位置上积木的编号。编号为不超过 10^6
的正整数，数字间以空格分隔。题目保证不同积木的编号是不同的。 输出格式:

在一行中输出按照题目限定可以拆卸积木的顺序。数字间以 1
个空格分隔，行首尾不得有多余空格。如果拆卸到某一步发现无法继续了，则在对应位置上输出
Impossible，然后结束。 输入样例 1（示意如上图）:

5 5
4 4 4 11 11
9 9 4 2 1
9 5 4 4 4
7 3 3 6 10
8 8 8 10 10

输出样例 1:

11 1 2 4 6 9 5 3 7 8 10

输入样例 2:

4 3
8 9 7
4 4 4
5 6 4
1 4 4

输出样例 2:

7 8 9 Impossible
*/

/*
题目解析：典型的拓扑排序问题，只不过这里的图是一个二维的图，
我们可以将这个二维图转化为一个有向图，然后对这个有向图进行拓扑排序即可。
解题思路：首先我们需要建立一个有向图，然后对这个有向图进行拓扑排序，
最后输出拓扑排序的结果即可。
*/

#include <iostream>
#include <queue>
#include <vector>

using namespace std;

const int MAXN = 1000001;

vector<short> inDegree(MAXN, -1);
vector<int> outNodes[MAXN];

void swap(int *&p1, int *&p2) {
    int *t = p1;
    p1 = p2;
    p2 = t;
}

void buildGraph(int N, int M) {
    int l1[M], l2[M];
    int *p1 = l1, *p2 = l2;

    for (int i = 0; i < M; i++) {
        int x;
        cin >> x;
        // nodes[x].id = x;
        inDegree[x] = 0;
        p1[i] = x;
    }
    for (int i = 0; i < N - 1; i++) {
        for (int j = 0; j < M; j++) {
            int x;
            cin >> x;
            p2[j] = x;
            if (p1[j] != p2[j]) {
                // nodes[x].id = x;
                if (inDegree[x] < 0) {
                    inDegree[x] = 0;
                }
                inDegree[x]++;
                outNodes[p1[j]].push_back(p2[j]);
                // nodes[p2[j]].inDegree = 0;
            }
        }
        swap(p1, p2);
    }
}

bool topSort() {
    priority_queue<int, vector<int>, greater<int>> q;
    int num_vertex = 0;
    for (int i = 0; i < MAXN; i++) {
        outNodes[i].shrink_to_fit();
        if (inDegree[i] >= 0) {
            num_vertex++;
            if (inDegree[i] == 0) {
                q.push(i);
            }
        }
    }

    if (q.empty()) {
        cout << "Impossible" << endl;
        return false;
    }

    bool first = true;
    int cnt = 0;
    while (!q.empty()) {
        int v = q.top();
        q.pop();
        if (!first) {
            cout << " ";
        }
        cout << v;
        first = false;
        cnt++;
        for (auto u : outNodes[v]) {
            inDegree[u]--;
            if (inDegree[u] == 0) {
                q.push(u);
            }
        }
        outNodes[v].clear();
        outNodes[v].shrink_to_fit();
    }
    if (cnt != num_vertex) {
        cout << " Impossible" << endl;
        return false;
    }
    return true;
}

int main() {
    int N, M;
    cin >> N >> M;
    buildGraph(N, M);
    topSort();
    return 0;
}
